package org.darcy.service.sys.impl;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.FilenameUtils;
import org.darcy.config.properties.OssClientProperties;
import org.darcy.config.properties.UploadProperties;
import org.darcy.entity.sys.SysFile;
import org.darcy.framework.enm.UploadType;
import org.darcy.framework.exception.BusinessException;
import org.darcy.service.sys.OssService;
import org.darcy.service.sys.SysFileService;
import org.darcy.service.sys.UploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class UploadServiceImpl implements UploadService {

	@Autowired
	private SysFileService sysFileService;

	@Autowired
	private UploadProperties p;

	@Autowired
	private OssService OssService;

	@Override
	public SysFile upload(String type, MultipartFile multipartFile) throws BusinessException {
		String originalFilename = multipartFile.getOriginalFilename();
		long size = multipartFile.getSize();
		double kb = size * 1.00 / 1024;
		BigDecimal sizeMb = NumberUtil.round(kb, 2);
		// 获取文件后缀
		String extension = FilenameUtils.getExtension(originalFilename);
		// 校验业务类型
		checkUploadType(type, sizeMb, extension);

		SysFile sysFile = new SysFile();
		sysFile.setFileType(type);
		sysFile.setFileName(originalFilename);
		sysFile.setFileSize(sizeMb.toString());

		String url = null;
		// 本地上传
		if (p.getType() == 0) {
			File localFile = getLocalFile(originalFilename);
			try {
				multipartFile.transferTo(localFile);
			} catch (IllegalStateException e) {
				log.error("文件上传出错，IllegalStateException", e);
				throw new BusinessException("文件上传出错，IllegalStateException");
			} catch (IOException e) {
				log.error("文件上传出错，IOException", e);
				throw new BusinessException("文件上传出错，IOException");
			}
			url = localFile.getPath().replace(p.getPath(), p.getHost()).replace(p.getPathWindows(), p.getHost());
		}
		// oss上传
		if (p.getType() == 1) {
			String key = getOssFileName(originalFilename);
			try {
				OssService.upload(key, multipartFile.getInputStream());
			} catch (Exception e) {
				log.error("上传阿里云oss失败", e);
			}
			OssClientProperties clientInfo = p.getAliyun();
			String host = "https://" + clientInfo.getBucketName() + "."
					+ clientInfo.getEndpoint().substring(clientInfo.getEndpoint().lastIndexOf("/") + 1);
			url = host + "/" + key;
		}
		sysFile.setUrl(url);

		sysFileService.insert(sysFile);
		log.debug("文件上传：文件大小={0}, 文件路径={1}", sizeMb.toString(), url);
		return sysFile;
	}

	private File getLocalFile(String originalFilename) {
		// 上传目录名称：年月
		String uploadDirName = DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN);
		// 文件名称：年月日时分秒+15位唯一ID
		String formatDate = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
		String extension = FilenameUtils.getExtension(originalFilename);
		String newFileName = formatDate + IdWorker.getId() + "." + extension;

		// 本地文件上传路径
		File uploadRootDir = new File(p.getPath());
		// 上传目录不存在，则直接创建
		if (!uploadRootDir.exists()) {
			uploadRootDir.mkdirs();
		}
		File uploadDir = new File(uploadRootDir, uploadDirName);
		if (!uploadDir.exists()) {
			uploadDir.mkdirs();
		}
		File uploadFile = new File(uploadDir, newFileName);
		return uploadFile;
	}

	private String getOssFileName(String originalFilename) {
		// 文件名称：年月日时分秒+15位唯一ID
		String formatDate = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
		String extension = FilenameUtils.getExtension(originalFilename);
		String newFileName = formatDate + IdWorker.getId() + "." + extension;
		return newFileName;
	}

	@Override
	public List<SysFile> uploadBatch(String type, List<MultipartFile> multipartFiles) throws BusinessException {
		List<SysFile> uploadVos = new ArrayList<>();
		for (MultipartFile multipartFile : multipartFiles) {
			SysFile upload = upload(type, multipartFile);
			uploadVos.add(upload);
		}
		return uploadVos;
	}

	private void checkUploadType(String type, BigDecimal sizeMb, String extension) throws BusinessException {
		UploadType uploadType = UploadType.get(type);
		Integer maxSizeMb = uploadType.getMaxSizeMb();
		Integer maxSizeKb = maxSizeMb * 1024;
		List<String> extensions = uploadType.getExtensions();
		if (sizeMb.doubleValue() > maxSizeKb) {
			throw new BusinessException("超过文件大小限制，请上传" + maxSizeMb + "MB以内的文件");
		}
		extension = extension.toLowerCase();
		if (extensions != null && !extensions.contains(extension)) {
			throw new BusinessException("文件格式错误，请上传" + extensions.toString() + "格式的文件");
		}
	}

	@Override
	public SysFile upload(String base64) throws BusinessException {
		// 有时Base64数据可能包含数据头，如:data:image/png;base64,需要先去除
		if (base64.contains(",")) {
			base64 = base64.split(",")[1];
		}
		// 解码并保存文件
		byte[] fileBytes = Base64.getDecoder().decode(base64);
		long size = fileBytes.length;
		double kb = size * 1.00 / 1024;
		BigDecimal sizeMb = NumberUtil.round(kb, 2);

		// 确定文件保存路径
		File localFile = getLocalFile("图片预览.jpg");
		Path filePath = Paths.get(localFile.getAbsolutePath());

		// 确保目录存在
		try {
			Files.createDirectories(filePath.getParent());
			// 写入文件
			Files.write(filePath, fileBytes);
		} catch (IOException e) {
			e.printStackTrace();
		}

		// 文件的网络访问路径
		String url = localFile.getPath().replace(p.getPath(), p.getHost()).replace(p.getPathWindows(), p.getHost());

		SysFile sysFile = new SysFile();
		sysFile.setUrl(url);
		sysFile.setFileSize(sizeMb.toString());
		sysFileService.insert(sysFile);
		log.debug("文件上传：文件大小={0}, 文件路径={1}", sizeMb.toString(), url);
		return sysFile;
	}

}
